/* * Sun Public License Notice * * The contents of this file are subject to the Sun Public License * Version 1.0 (the "License"). You may not use this file except in * compliance with the License. A copy of the License is available at * http://www.sun.com/ * * The Original Code is Forte for Java, Community Edition. The Initial * Developer of the Original Code is Sun Microsystems, Inc. Portions * Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved. */ package org.openide.src.nodes; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeEvent; import java.util.Comparator; import java.util.Collection; import java.util.Collections; import java.util.LinkedList; import java.util.Arrays; import java.util.HashMap; import org.openide.nodes.Children; import org.openide.nodes.Node; import org.openide.cookies.FilterCookie; import org.openide.util.WeakListener; import org.openide.src.*; /** Normal implementation of children list for a class element node. * Semantics are similar to those of {@link SourceChildren}. * @author Dafe Simonek, Jan Jancura */ public class ClassChildren extends Children.Keys implements FilterCookie { /** Support for PACKAGE modifier */ private static int PPP_MASK = SourceElementFilter.PUBLIC + SourceElementFilter.PRIVATE + SourceElementFilter.PROTECTED; /** Converts property names to filter. * @associates Integer*/ protected static HashMap propToFilter; /** For sorting groups of elements. */ private static Comparator comparator = new Comparator () { public int compare (Object o1, Object o2) { if (o1 instanceof MemberElement) if (o2 instanceof MemberElement) return ((MemberElement) o1).getName ().getName ().compareToIgnoreCase ( ((MemberElement) o2).getName ().getName () ); else return -1; else if (o2 instanceof MemberElement) return 1; else return 0; } }; static { propToFilter = new HashMap (); propToFilter.put (ElementProperties.PROP_CLASSES, new Integer (ClassElementFilter.CLASS | ClassElementFilter.INTERFACE)); propToFilter.put (ElementProperties.PROP_METHODS, new Integer (ClassElementFilter.METHOD)); propToFilter.put (ElementProperties.PROP_FIELDS, new Integer (ClassElementFilter.FIELD)); propToFilter.put (ElementProperties.PROP_CONSTRUCTORS, new Integer (ClassElementFilter.CONSTRUCTOR)); propToFilter.put (ElementProperties.PROP_INITIALIZERS, new Integer (ClassElementFilter.CONSTRUCTOR)); } /** The class element whose subelements are represented. */ protected ClassElement element; /** Filter for elements, or <code>null</code> to disable. */ protected ClassElementFilter filter; /** Factory for creating new child nodes. */ protected ElementNodeFactory factory; /** Weak listener to the element and filter changes */ private PropertyChangeListener wPropL; /** Listener to the element and filter changes. This reference must * be kept to prevent the listener from finalizing when we are alive */ private ElementListener propL; /** Central memory of mankind is used when some elements are changed */ protected Collection[] cpl; /** Flag saying whether we have our nodes initialized */ private boolean nodesInited = false; // init ................................................................................ /** Create class children with the default factory. * The children are initially unfiltered. * @param element attached class element (non-<code>null</code>) */ public ClassChildren (final ClassElement element) { this(DefaultFactory.READ_WRITE, element); } /** Create class children. * The children are initially unfiltered. * @param factory the factory to use to create new children * @param element attached class element (non-<code>null</code>) */ public ClassChildren (final ElementNodeFactory factory, final ClassElement element) { super(); this.element = element; this.factory = factory; this.filter = null; } /********** Implementation of filter cookie **********/ /* @return The class of currently asociated filter or null * if no filter is asociated with these children. */ public Class getFilterClass () { return ClassElementFilter.class; } /* @return The filter currently asociated with these children */ public Object getFilter () { return filter; } /* Sets new filter for these children. * @param filter New filter. Null == disable filtering. */ public void setFilter (final Object filter) { if (!(filter instanceof ClassElementFilter)) throw new IllegalArgumentException(); this.filter = (ClassElementFilter)filter; // change element nodes according to the new filter if (nodesInited) refreshAllKeys (); } // Children implementation .............................................................. /* Overrides initNodes to run the preparation task of the * source element, call refreshKeys and start to * listen to the changes in the element too. */ protected void addNotify () { refreshAllKeys (); // listen to the changes in the class element if (wPropL == null) { propL = new ElementListener(); wPropL = WeakListener.propertyChange (propL, element); } element.addPropertyChangeListener (wPropL); nodesInited = true; } protected void removeNotify () { setKeys (java.util.Collections.EMPTY_SET); nodesInited = false; } /* Creates node for given key. * The node is created using node factory. */ protected Node[] createNodes (final Object key) { if (key instanceof MethodElement) { return new Node[] { factory.createMethodNode((MethodElement)key) }; } if (key instanceof FieldElement) { return new Node[] { factory.createFieldNode((FieldElement)key) }; } if (key instanceof ConstructorElement) { return new Node[] { factory.createConstructorNode((ConstructorElement)key) }; } if (key instanceof ClassElement) { return new Node[] { factory.createClassNode((ClassElement)key) }; } if (key instanceof InitializerElement) { return new Node[] { factory.createInitializerNode((InitializerElement)key) }; } // ?? unknown type return new Node[0]; } /************** utility methods ************/ /** Updates all the keys (elements) according to the current filter & * ordering. */ protected void refreshAllKeys () { cpl = new Collection [getOrder ().length]; refreshKeys (ClassElementFilter.ALL); } /** Updates all the keys with given filter. */ protected void refreshKeys (int filter) { int[] order = getOrder (); LinkedList keys = new LinkedList(); // build ordered and filtered keys for the subelements for (int i = 0; i < order.length; i++) { if (((order[i] & filter) != 0) || (cpl [i] == null)) keys.addAll (cpl [i] = getKeysOfType (order[i])); else keys.addAll (cpl [i]); } // set new keys setKeys(keys); } /** Filters and returns the keys of specified type. */ protected Collection getKeysOfType (final int elementType) { LinkedList keys = new LinkedList(); if ((elementType & ClassElementFilter.EXTENDS) != 0) { keys.add (element.getSuperclass ()); } if ((elementType & ClassElementFilter.IMPLEMENTS) != 0) { keys.addAll (Arrays.asList (element.getInterfaces ())); } if ((elementType & ClassElementFilter.FIELD) != 0) { filterModifiers (element.getFields (), keys); } if ((elementType & ClassElementFilter.CONSTRUCTOR) != 0) { filterModifiers (element.getConstructors (), keys); keys.addAll (Arrays.asList (element.getInitializers ())); } if ((elementType & ClassElementFilter.METHOD) != 0) { filterModifiers (element.getMethods (), keys); } if ((elementType & (ClassElementFilter.CLASS + ClassElementFilter.INTERFACE)) != 0) { filterClassModifiers (element.getClasses (), keys, elementType); } if ((filter == null) || filter.isSorted ()) Collections.sort (keys, comparator); return keys; } /** Returns order form filter. */ protected int[] getOrder () { return (filter == null || (filter.getOrder() == null)) ? ClassElementFilter.DEFAULT_ORDER : filter.getOrder(); } /** Returns modifier filter form filter. */ private int getModifierFilter () { if (filter == null) return ClassElementFilter.ALL_MODIFIERS; return filter.getModifiers (); } /** Filters MemberElements for modifiers, and adds them to the given collection. */ private void filterModifiers (MemberElement[] elements, Collection keys) { int ff = getModifierFilter (); int i, k = elements.length; for (i = 0; i < k; i ++) { int f = elements [i].getModifiers (); if ((f & PPP_MASK) == 0) f += ClassElementFilter.PACKAGE; if ((f & ff) != 0) keys.add (elements [i]); } } /** Filters ClassElements for their type, and adds them to the given collection. */ private void filterClassModifiers (ClassElement[] elements, Collection keys, int filter) { int ff = getModifierFilter (); int i, k = elements.length; for (i = 0; i < k; i ++) { int f = elements [i].getModifiers (); if ((f & PPP_MASK) == 0) f += ClassElementFilter.PACKAGE; if ((f & ff) == 0) continue; if (elements [i].isClass ()) { if ((filter & ClassElementFilter.CLASS) != 0) keys.add (elements [i]); } else if ((filter & ClassElementFilter.INTERFACE) != 0) keys.add (elements [i]); } } // innerclasses ........................................................................... /** The listener for listening to the property changes in the filter. */ private final class ElementListener implements PropertyChangeListener { /** This method is called when the change of properties occurs in the element. * PENDING - (for Hanz - should be implemented better, change only the * keys which belong to the changed property). * -> YES MY LORD! ANOTHER WISH? */ public void propertyChange (PropertyChangeEvent evt) { Integer i = (Integer) propToFilter.get (evt.getPropertyName ()); if (i != null) refreshKeys (i.intValue ()); } } // end of ElementListener inner class } /* * Log * 24 src-jtulach1.23 11/5/99 Jaroslav Tulach WeakListener has now * registration methods. * 23 src-jtulach1.22 10/22/99 Ian Formanek NO SEMANTIC CHANGE - Sun * Microsystems Copyright in File Comment * 22 src-jtulach1.21 9/13/99 Petr Hamernik fixed bug in changes of * interfaces * 21 src-jtulach1.20 7/19/99 Jan Jancura * 20 src-jtulach1.19 7/1/99 Jan Jancura Support for sorting * 19 src-jtulach1.18 6/8/99 Ian Formanek ---- Package Change To * org.openide ---- * 18 src-jtulach1.17 5/16/99 Jaroslav Tulach System.out commented * 17 src-jtulach1.16 5/15/99 Jaroslav Tulach Changes in hierarchy to * work better in DataObjectFilter * 16 src-jtulach1.15 4/22/99 Jaroslav Tulach The previous version was * good. * 15 src-jtulach1.14 4/21/99 Jan Jancura Rolled back - bug in * parsing * 14 src-jtulach1.13 4/21/99 Jan Jancura Optimalization in * Children.Keys applied * 13 src-jtulach1.12 4/16/99 Jaroslav Tulach Changes in children. * 12 src-jtulach1.11 4/16/99 Jan Jancura * 11 src-jtulach1.10 4/6/99 Petr Hamernik order of children changed * (innerclasses are last) * 10 src-jtulach1.9 4/2/99 Jesse Glick [JavaDoc] * 9 src-jtulach1.8 4/2/99 Jan Jancura ObjectBrowser Support * 8 src-jtulach1.7 3/16/99 Petr Hamernik renaming static fields * 7 src-jtulach1.6 3/15/99 Petr Hamernik * 6 src-jtulach1.5 3/10/99 Petr Hamernik small bug-fix * 5 src-jtulach1.4 2/9/99 David Simonek * 4 src-jtulach1.3 2/9/99 David Simonek little fixes - init in * separate thread * 3 src-jtulach1.2 2/3/99 David Simonek * 2 src-jtulach1.1 2/3/99 David Simonek getting it to work * properly * 1 src-jtulach1.0 1/29/99 David Simonek * $ */